<html><head>

<script type="text/javascript" src="http://api.msappspace.com/JSLoader/JSLoader.aspx?v=0.7&f=rpc&appid={{ appid }}&ownerId={{ ownerId }}&localRelay=http://opensocial--tic-tac-toe.appspot.com/relay/ifpc_relay_external001.html"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.3/prototype.js"></script>

<script type="text/javascript">

/**
 * Tic-Tac-Toe static object controller namespace
 */
var TTT = {
   Keys: {
       NAME: "name",
       SCORE: "score"
   },
   RequestKeys: {
       VIEWERDATA: "viewer_data",
       VIEWER: "v",
       VIEWER_FRIENDS: "vf",
       VIEWER_PHOTOS: "vp"
   },
   Players: {
       Computer: "O",
       Human: "X"
   }
};

TTT.Tab = function(tab_dom, container, action){
   this.tab_dom = tab_dom;
   this.container = container;
   
   if(this.container){
      this.container.hide = function(){
         this.style.display = "none";
      }
      
      this.container.show = function(){
         this.style.display = "block";
      }
   }
   
   this.action = action;
};

TTT.Tabs = {
   _tabs:[],
   
   _selectedTab:null,
   
   _initTabs:function(){
      this._tabs[0] = new TTT.Tab(document.getElementById("tab1"), document.getElementById("invite_container"), function(){});
   },
   
   getCurrentContainer:function(){
      return this._tabs[this._selectedTab].container;
   },
   
   getCurrentTab:function(){
      return this._tabs[this._selectedTab];
   },
   
   selectTab:function(index){
      if(0 === this._tabs.length){
         this._initTabs();
      }

      if(index !== this._selectedTab){
         this._tabs[index].tab_dom.className += " tab_selected";
         
         var selected = this._tabs[this._selectedTab];
         if(null !== this._selectedTab){
            var ind = selected.tab_dom.className.indexOf(" tab_selected");
            selected.tab_dom.className = selected.tab_dom.className.substr(0, ind);
            
            selected.container.hide();
         }
         this._selectedTab = index;
         
         this._tabs[index].container.show();
         this._tabs[index].action();
      }
   }
};

TTT.List = function(list_type, id_key, name_key, image_key, class_name, item_onclick){
   this.list_type = list_type;
   this.list = [];
   this.list_dom = {};
   this.first = 1;
   this.max = 20;
   this.total = 0;
   this.retries = 3;
   
   this.id_key = id_key;
   this.name_key = name_key;
   this.image_key = image_key;
   this.class_name = class_name;
   this.item_onclick = item_onclick;
};

TTT.ListTypes = {
   ALL_FRIENDS:"ALL_FRIENDS",
   HASAPP_FRIENDS:"HASAPP_FRIENDS",
   SET_BACKGROUND:"SET_BACKGROUND"
};

TTT.Lists = {
   _current:"",
   
   itemClicked:[],
   
   getCurrentList:function(){
      for(var key in this.lists){
         if(this.lists[key].list_type === this._current){
            return this.lists[key];
         }
      }
   },
   
   setCurrentList:function(list_type){
      this._current = list_type;
   },
   
   lists:{
      all_friends:new TTT.List(TTT.ListTypes.ALL_FRIENDS, opensocial.Person.Field.ID, opensocial.Person.Field.NICKNAME, opensocial.Person.Field.THUMBNAIL_URL, "friend", rsaInviteClicked)
   },
   
   markup_format:"<div><img src='{0}' /></div>{1}",
   
   permCallback:function(response){
      if(!response.hadError()){
         TTT.Lists.retryRequest();
      }
   },
   
   retryRequest:function(){
      TTT.Lists.getCurrentList().retries--;
      window.setTimeout(TTT.Tabs.getCurrentTab().action, 250);
   }
};

TTT.Lists.draw = function(){
   var div, id, name, picture;
   
   // create a container to insert all the items into
   var all_items = document.createElement("div");
   
   var current_list = this.getCurrentList();
   
   // display a message if the list is empty
   if(0 === current_list.list.length){
      TTT.Tabs.getCurrentContainer().innerHTML = "Oops, no results to show!";
      return;
   }
   
   // add the pager markup
   all_items.innerHTML = TTT.Lists.Pager.getMarkUp();

   for(var i = 0; i < current_list.list.length; i++){
      id = current_list.list[i].userId;
      name = current_list.list[i].name;
      picture = current_list.list[i].image;

      // create the item's div element      
      div = document.createElement("div");
      div.className = current_list.class_name;
      div.onclick = current_list.item_onclick;
      div.list_index = id;
      var friend = this.markup_format.replace("{0}", picture);
      friend = friend.replace("{1}", name);
      div.innerHTML = friend;
      
      // append it to the container
      all_items.appendChild(div);
      
      // save a reference to the element
      current_list.list_dom[id] = div;
   }
   
   // add a clearing div since we're using css floats
   div = document.createElement("div");
   div.className = "clear";
   all_items.appendChild(div);
   
   var save_first_child = TTT.Tabs.getCurrentContainer().firstChild.innerHTML;
   TTT.Tabs.getCurrentContainer().innerHTML = "<div>" + save_first_child + "</div>";
   
   // add all the items at once to the current tab, doing it all
   // at once means that we only update the DOM once
   TTT.Tabs.getCurrentContainer().appendChild(all_items);
};

TTT.Lists.callback = function(response){
   var current_list = TTT.Lists.getCurrentList();
   
   var retryRequest = function(){
      current_list.retries--;
      window.setTimeout(fetchFriends, 250);
   };
   
   // check for errors
   if(!response 
            || !response.responseJSON 
            || response.responseJSON.errorCode
            || !response.responseJSON.Friends){
      if(current_list.retries > 0){
         retryRequest();
      }
      // out of retries...
      else{
         log("Oops, there was an error! Try refreshing the page.");
      }
	  
	  return;
   }
   
   var data = response.responseJSON.Friends;

   // something bad happened to it
   if(null === data || "undefined" === typeof(data)){
      retryRequest();
      return;
   }
   else{
      // save the actual data to the TTT.List object
      current_list.list = data;

      // save the total number of items in the list
      current_list.total = response.responseJSON.count;

      // draw the list
      TTT.Lists.draw();
   }
};

TTT.Lists.Pager = {
   pager_wrap:"<div class='pager'>{0}</div>",
   pager_prev:"<span onclick='TTT.Lists.Pager.prev();'><< prev</span>&nbsp;",
   pager_next:"&nbsp;<span onclick='TTT.Lists.Pager.next();'>next >></span>",
   page_size:20,
   
   getMarkUp:function(){
      var current_list = TTT.Lists.getCurrentList();
      
      if(current_list.list.length < this.page_size && 
               1 === current_list.first){
         // if the length is less than the amount requested
         // there is only one page, no need for a pager
         return "";
      }
      
      var markup = "";
      
      if(current_list.first > 1){
         // if the first index is greater than 1
         // then there will be a previous page
         markup += this.pager_prev;
      }
      
      if(((current_list.first - 1) * this.page_size) + current_list.list.length
               < current_list.total){
         // if the total number of records is greater than
         // the number of records fetched so far, then 
         // there's a next page.
         markup += this.pager_next;
      }
      
      if(markup.length > 0){
         markup = this.pager_wrap.replace("{0}", markup);
      }
      
      return markup;
   },
   prev:function(){
      var current_list = TTT.Lists.getCurrentList();
      
      current_list.first--;
      fetchFriends(current_list.list_type);
   },
   next:function(){
      var current_list = TTT.Lists.getCurrentList();
      
      current_list.first++;
      fetchFriends(current_list.list_type);
   }
};


var retries = 3;
var debug = true;
var friends = {{ friends_obj }};

/**
 * Output an error message if debug mode is enabled
 * @param {String} message
 */
function log(message){
   var errFeed = document.getElementById("messages");
   if(errFeed){
      errFeed.innerHTML += message + "<br />";
   }
}

function fetchFriends(list_type){
   var current_list = TTT.Lists.getCurrentList();
   
   var filter = "";
   if(TTT.ListTypes.HASAPP_FRIENDS === list_type){
      filter = opensocial.DataRequest.FilterType.HAS_APP;
   }
   
   fetchFriendList(current_list.first, current_list.max, TTT.Lists.callback, filter);
}

// fetch a list of friends, given the various
// parameters
function fetchFriendList(first, max, callback, filter, sort){
   // build the URL
   var url = "/friends?id=" + friends.user.userId;
   url += "&first=" + first + "&max=" + max;
   
   // use prototype's Ajax object
   new Ajax.Request(url, {
      method: 'get',
      onSuccess: callback,
      onFailure: callback
   });
}

function raiseActivity(){
   // create the parameters
   var param = {};
   
   // required template name
   param[opensocial.Activity.Field.TITLE_ID] = "x_and_y_started_game";
   
   // the actual parameter values
   param[opensocial.Activity.Field.TEMPLATE_PARAMS] = {
      "opponent" : currentGame.opponentId,
      "params" : "{\"from\":\"act\"}"
   };

   // check if a custom background is set to use for
   // a media item
   if(currentGame.customBG.usingCustomBG()){
      // get the photo object
      var photo = currentGame.customBG.photo;
      
      // parse out the URI
      var uri = photo.getField(MyOpenSpace.Photo.Field.PHOTO_URI);
      
      // create the opensocial.MediaItem object
      var media_item = opensocial.newMediaItem("image/jpeg", uri)
      
      // stick it in an array
      var media_item_array = [ media_item ];
      
      // insert the array into the parameters
      param[opensocial.Activity.Field.MEDIA_ITEMS] = media_item_array;
   }
   
   // create the opensocial.Activity object
   var activity = opensocial.newActivity(param);
   
   // raise the activity!
   opensocial.requestCreateActivity(activity, 
         opensocial.CreateActivityPriority.HIGH, raiseActivityCallback);
}

function raiseActivityCallback(response) {
   // check for an error
   if(response.hadError()){
   
      // was the error a permission issue?
      if(response.getErrorCode() === 
            opensocial.ResponseItem.Error.UNAUTHORIZED){
            
         // beg for permission
         var reason = "To inform your friends of your upcoming match!";
         
         // pick which permission
         // STICK IT IN AN ARRAY!!
         var perm = [MyOpenSpace.Permission.VIEWER_SEND_UPDATES_TO_FRIENDS];
         
         // pretty please...
         opensocial.requestPermission(perm, reason, actPermCallback);
      }
      else{
         // some other error
         log("Oops, there was an error, try refreshing!");
      }
   }
}

function actPermCallback(response){
   // was permission granted?
   if(!response.hadError()){
      // yay!
      raiseActivity();
   }
}

// wrap 0.7's postTo functionality
function postToWrapper(person, subject, body, type, callback){
   // create the opensocial.Message as normal
   var param = {};
   param[opensocial.Message.Field.TYPE] = type;
   param[opensocial.Message.Field.TITLE] = subject;
   
   var message = opensocial.newMessage(body, param);
   
   // create an opensocial.Name object
   param = {};
   param[opensocial.Name.Field.UNSTRUCTURED] = person.name;
   var name = new opensocial.Name(param);
   
   // then the opensocial.Person object
   param = {};
   param[opensocial.Person.Field.ID] = person.userId;
   param[opensocial.Person.Field.NAME] = name;
   param[opensocial.Person.Field.PROFILE_URL] = person.webUri;
   param[opensocial.Person.Field.THUMBNAIL_URL] = person.image;
   var recipient = new opensocial.Person(param);
   
   // set the token
   MyOpenSpace.MySpaceContainer.OSToken = "{{ opensocial_token }}";
   
   // call postTo
   opensocial.Container.get().postTo("", message, recipient, callback);
}

function rsmBulletin(){
   var this_app = opensocial.getEnvironment().currentApplication;
   var canvas_link = 
         "http://profile.myspace.com/Modules/Applications/Pages/Canvas.aspx?appId={{ appid }}";
   
   var subject = "Social Tic-Tac-Toe is Here!";
   
   var body = "Hey everyone! I'm playing TTT online with my friends, come ";
   body += "<a href='" + canvas_link + "'>play a game</a> with me!";
   
   postToWrapper(friends.user, subject, body, 
         opensocial.Message.Type.NOTIFICATION, rsmBulletinCallback);
}

function rsmBulletinCallback(response){
   var div = TTT.Tabs.getCurrentContainer().firstChild;
   
   if("undefined" !== typeof(response)){
      if(0 === response){
         if(div.innerHTML.indexOf(" cancelled...") < 0){
            div.innerHTML += " cancelled...";
         }
      }
      else if(1 === response){
         div.innerHTML = "bulletin sent";
      }
   }
   else{
      log("Oops, there was an error with the bulletin, try refreshing the page!");
   }
}

function rsaInviteClicked(){
   var id = this.list_index;
   
   if(TTT.Lists.itemClicked.constructor === Array){
      var found = false;
      for(var i = 0; i < TTT.Lists.itemClicked.length; i++){
         if(TTT.Lists.itemClicked[i] === id){
            found = true;
         }
      }
      
      if(!found){
         TTT.Lists.itemClicked.push(id);
      }
   }
   else{
      TTT.Lists.itemClicked = [id];
   }
   
   var clicked = TTT.Lists.getCurrentList().list_dom[id];
   clicked.style.backgroundColor = "yellow";
}

function requestShareAppWrapper(id, body, callback){
   var person = null;
   
   for(var i = 0; i < friends.Friends.length; i++){
      if(friends.Friends[i].userId === id){
         person = friends.Friends[i];
         break;
      }
   }

   if(null !== person){
      postToWrapper(person, "", body, MyOpenSpace.PostTo.Targets.SHARE_APP, callback);
   }
}

// finds the correct friend from the REST API response
function requestSendMessageWrapper(id, subject, body, type, callback){
   var person = null;
   
   // loop through the list of friends
   for(var i = 0; i < friends.Friends.length; i++){
   
      // if the ID is found in the list
      if(friends.Friends[i].userId === id){
      
         // save the person
         person = friends.Friends[i];
         break;
      }
   }

   if(null !== person){
      postToWrapper(person, subject, body, type, callback);
   }
}

function rsaInviteButtonClicked(){
   // TTT.Lists.itemClicked contains the list of friends
   // that were clicked
   if(TTT.Lists.itemClicked.length > 0){
   
      // take the ID of the first friend that was clicked
      var id = TTT.Lists.itemClicked[0];
      
      // create some catchy body text
      var body = "Hi [recipient]... [sender] wants you to come";
      body += " play Tic-Tac-Toe, add [app] now!";
      
      // then pass the values into our wrapper
      requestShareAppWrapper(id, body, rsaWrapperCallback);
   }
}

function rsaWrapperCallback(response){
   // get the first clicked friend
   var current_list = TTT.Lists.getCurrentList();
   clicked = current_list.list_dom[TTT.Lists.itemClicked[0]];
   
   // check for some kind of bad response, and show an error message
   if("undefined" === typeof(response)){
      log("Oops, there was an error, try refreshing the page!");
   }
   else{
   
      // was the popup cancelled?
      if(0 === response){
      
         // if so, stop looping through the list and revert
         // all the friend boxes to a white background
         for(var i = 0; i < TTT.Lists.itemClicked.length; i++){
            clicked = current_list.list_dom[TTT.Lists.itemClicked[i]];
            clicked.style.backgroundColor = "white";
         }
         
         // reset the list
         TTT.Lists.itemClicked = [];
      }
      else{
      
         // otherwise the share request was sent,
         // remove the first friend
         TTT.Lists.itemClicked.splice(0, 1);
         
         // remove the friend box from the DOM to
         // make it clear it was sent
         if(clicked.parentNode){
            clicked.parentNode.removeChild(clicked);
         }
         
         // start the process again
         rsaInviteButtonClicked();
      }
   }
}

function runOnLoad(){
   TTT.Lists.setCurrentList(TTT.ListTypes.ALL_FRIENDS);
   TTT.Lists.getCurrentList().list = friends.Friends;
   TTT.Lists.getCurrentList().total = friends.count;
   TTT.Tabs.selectTab(0);
   TTT.Lists.draw();
}

</script>
</head>

<body onload="runOnLoad()">
	<div id="overlay"></div>
	<div id="light_box_container"><div id="light_box"></div></div>
	
	<div class="container">
	   <h1>OpenSocial Tic-Tac-Toe</h1>
	   
	   <div>
	      <div class="left tab_spacer small_width">&nbsp;</div>
	      <a id="tab0" class="left tab" href="/play?opensocial_viewer_id={{ ownerId }}&appid={{ appid }}&opensocial_token={{ opensocial_token }}">Play</a>
	      <div id="tab1" class="left tab tab_selected tab_last">Invite</div>
	      <div class="left tab_spacer large_width">&nbsp;</div>
	      <div class="clear"></div>
	   </div>
	</div>
	
	<div id="invite_container" class="container"><div><button onclick="rsmBulletin();">Send a Bulletin!</button>&nbsp;<button onclick="rsaInviteButtonClicked();">Send Invite(s)</button></div></div>
	
	<div id="messages"></div>
	
	<style>
	   img
	   {
	      border:0;
	   }
	   body
	   {
	      margin:0;
	      padding:0;
	      font-family:Verdana;
	      font-size:12pt;
	   }
	   
	   #gameboard
	   {
          margin:10px;
	      border-collapse: collapse;
	      border:2px solid black;
	      padding:5px;
	      margin-bottom:5px;
	      empty-cells:show;
	      font-size: 40pt;
	      font-family:Verdana;
	      font-weight:bold;
	      color:#fff;
	      cursor:pointer;
	   }
	   #gameboard td
	   {
	      color:#fff;
	      border:1px solid white;
	      text-align:center;
	      width:120px;
	      height:120px;
	   }
	   .container
	   {
	   	  margin:10px;
	   }
	   .tab
	   {
	      border:solid 1px black;
	      border-right:0;
	      padding:5px 5px 4px;
	      cursor:pointer;
	      background-color:#ddd;
		  color:black;
		  text-decoration:none;
	   }
	   .tab_last
	   {
	      border-right:solid 1px black;
	   }
	   .tab_spacer
	   {
	      border-bottom:solid 1px black;
	      padding:5px;
	   }
	   .small_width
	   {
	      width:40px;
	   }
	   .large_width
	   {
	      width:50%;
	   }
	   .tab_selected
	   {
	      border-bottom:0;
	      background-color:white;
	   }
	   .friend
	   {
	      border:solid 1px black;
	      margin:5px;
	      padding:5px;
	      float:left;
	      width:90px;_width:102px;
	      overflow:hidden;
	      text-align:center;
	      height:160px;
	      cursor:pointer;
	   }
	   .photo
	   {
	      border:solid 1px black;
	      margin:5px;
	      padding:5px;
	      float:left;
	      width:130px;_width:142px;
	      overflow:hidden;
	      text-align:center;
	      height:130px;_height:142px;
	      cursor:pointer;
	   }
	   .photo img
	   {
	      width:130px;
	      height:110px;
	   }
	   .pager
	   {
	      font-size:9pt;
	   }
	   .pager span
	   {
	      color:blue;
	      cursor:pointer;
	   }
	   #messages
	   {
	      height:20px;
	      overflow:auto;
	      color:Red;
	   }
	   #right_column
	   {
	      float:right;
	      width:500px;
	   }
	   .right_column
	   {
	      float:right;
	      margin:5px;
	      width:100%;
	   }
	   .player_info
	   {
	      border:solid 2px black;
	      padding:5px;
	   }
	   .profile_image
	   {
	      margin:5px;
	      border:solid 1px black;
	   }
	   .more a
	   {
	      line-height:40px;
	      padding:5px;
	      border:solid 1px black;
	      cursor:pointer;
	      text-decoration:none;
	      color:Black;
	      background-color:White;
	   }
	   #overlay
	   {
	   	display:none;
	   	width:100%;
	   	height:100%;
	   	background-color:Black;
	   	left:0;
	   	top:0;
	   	z-index:100000;
	   	position:absolute;
	   	opacity:0.6;
	   	filter: alpha(opacity=60);
	   }
	   #light_box_container
	   {
	   	width:100%;
	   	left:0;
	   	position:absolute;
	   	top:70px;
	   	z-index:100001;
	   	text-align:center;
	   	display:none;
	   }
	   #light_box
	   {
	   	margin:auto;
	   	width:650px;
	   	background-color:White;
	   	border:solid 4px black;
	   	text-align:left;
	   }
	   #player_bio
	   {
	   	margin:5px;
	   }
	   #player_bio_title
	   {
	   	border-bottom:solid 1px black;
	   	font-weight:bold;
	   	padding:1px 0 5px 0;
	   	text-align:center;
	   }
	   #bio_close
	   {
	   	border-top:solid 1px black;
	   	margin-top:5px;
	   	padding:3px;
	   	text-align:center;
	   }
	   #bio_close a
	   {
	   	text-decoration:none;
	   }
	   .clear
	   {
	      clear:both;
	   }
	   .left
	   {
	      float:left;
	   }
	   .right
	   {
	      float:right;
	   }
	   .hide
	   {
	      display:none;
	   }
	   .record
	   {
	      font-size:12px;
	      text-align:center;
	   }
	</style>

</body></html>